bitkeeper revision 1.1662.1.7 (42a47555156iGoOjUyZtvbuMFZHXkg)
authorcl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>
Mon, 6 Jun 2005 16:09:57 +0000 (16:09 +0000)
committercl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>
Mon, 6 Jun 2005 16:09:57 +0000 (16:09 +0000)
XendDomainInfo.py:
  Move guest image handling into seperate file.
image.py:
  new file
Signed-off-by: Mike Wray <mike.wray@hp.com>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
.rootkeys
tools/python/xen/xend/XendDomainInfo.py
tools/python/xen/xend/image.py [new file with mode: 0644]

index a98c77a58fbc9bca0c45b378567ff6786eee751d..c0914886f0bf974cd9407979e12648243e59af44 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/python/xen/xend/XendVnet.py
 40c9c468x191zetrVlMnExfsQWHxIQ tools/python/xen/xend/__init__.py
 40c9c468S2YnCEKmk4ey8XQIST7INg tools/python/xen/xend/encode.py
+42a475165HuglqWwNi2fjqNOIHbIKQ tools/python/xen/xend/image.py
 4266169ezWIlXSfY50n6HSoVFbosmw tools/python/xen/xend/scheduler.py
 40c9c468IxQabrKJSWs0aEjl-27mRQ tools/python/xen/xend/server/SrvConsole.py
 40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/python/xen/xend/server/SrvConsoleDir.py
index 13c0aa0ef83caf7e330879a6abc83570b3a11a0a..f18b33134749086a0cc4832d54319a479274c8bb 100644 (file)
@@ -114,25 +114,6 @@ def get_config_handler(name):
     """
     return config_handlers.get(name)
 
-"""Table of handlers for virtual machine images.
-Indexed by image type.
-"""
-image_handlers = {}
-
-def add_image_handler(name, h):
-    """Add a handler for an image type
-    @param name:     image type
-    @param h:        handler: fn(config, name, memory, image)
-    """
-    image_handlers[name] = h
-
-def get_image_handler(name):
-    """Get the handler for an image type.
-    @param name:     image type
-    @return: handler or None
-    """
-    return image_handlers.get(name)
-
 """Table of handlers for devices.
 Indexed by device type.
 """
@@ -252,8 +233,6 @@ class XendDomainInfo:
         self.name = None
         self.memory = None
         self.image = None
-        self.ramdisk = None
-        self.cmdline = None
 
         self.channel = None
         self.controllers = {}
@@ -278,8 +257,6 @@ class XendDomainInfo:
         
         self.console_port = None
         self.savedinfo = None
-        self.image_handler = None
-        self.is_vmx = False
         self.vcpus = 1
         self.bootloader = None
 
@@ -330,8 +307,6 @@ class XendDomainInfo:
         console = self.getConsole()
         if console:
             s += " console=" + str(console.console_port)
-        if self.image:
-            s += " image=" + self.image
         s += ""
         return s
 
@@ -484,8 +459,8 @@ class XendDomainInfo:
             # Initial domain create.
             self.setName(sxp.child_value(config, 'name'))
             self.check_name(self.name)
+            self.init_image()
             self.configure_cpus(config)
-            self.find_image_handler()
             self.init_domain()
             self.register_domain()
             self.configure_bootloader()
@@ -527,29 +502,24 @@ class XendDomainInfo:
         except:
             raise VmError('invalid vcpus value')
 
-    def find_image_handler(self):
-        """Construct the boot image for the domain.
-
-        @return vm
+    def init_image(self):
+        """Create boot image handler for the domain.
         """
         image = sxp.child_value(self.config, 'image')
         if image is None:
             raise VmError('missing image')
-        image_name = sxp.name(image)
-        if image_name is None:
-            raise VmError('missing image name')
-        if image_name == "vmx":
-            self.is_vmx = True
-        image_handler = get_image_handler(image_name)
-        if image_handler is None:
-            raise VmError('unknown image type: ' + image_name)
-        self.image_handler = image_handler
-        return self
+        self.image = ImageHandler.create(self, image)
 
     def construct_image(self):
-        image = sxp.child_value(self.config, 'image')
-        self.image_handler(self, image)
-        return self
+        """Construct the boot image for the domain.
+        """
+        self.create_channel()
+        self.image.createImage()
+        #self.image.exportToDB()
+        #if self.store_channel:
+        #    self.db.introduceDomain(self.id,
+        #                            self.store_mfn,
+        #                            self.store_channel)
 
     def config_devices(self, name):
         """Get a list of the 'device' nodes of a given type from the config.
@@ -596,7 +566,7 @@ class XendDomainInfo:
         """Completely destroy the vm.
         """
         self.cleanup()
-        return self.destroy_domain()
+        self.destroy_domain()
 
     def destroy_domain(self):
         """Destroy the vm's domain.
@@ -606,9 +576,15 @@ class XendDomainInfo:
         if self.channel:
             self.channel.close()
             self.channel = None
+        if self.image:
+            try:
+                self.image.destroy()
+                self.image = None
+            except:
+                pass
         if self.id is None: return 0
         try:
-            return xc.domain_destroy(dom=self.id)
+            xc.domain_destroy(dom=self.id)
         except Exception, err:
             log.exception("Domain destroy failed: %s", self.name)
 
@@ -661,80 +637,11 @@ class XendDomainInfo:
             cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
         except:
             raise VmError('invalid cpu')
-        cpu_weight = self.cpu_weight
-        memory = memory * 1024 + self.pgtable_size(memory)
-        dom = xc.domain_create(dom= dom)
-        if self.bootloader:
-            try:
-                if kernel: os.unlink(kernel)
-                if ramdisk: os.unlink(ramdisk)
-            except OSError, e:
-                log.warning('unable to unlink kernel/ramdisk: %s' %(e,))
-
-        if dom <= 0:
-            raise VmError('Creating domain failed: name=%s memory=%d'
-                          % (self.name, memory))
-        xc.domain_setcpuweight(dom, cpu_weight)
-        xc.domain_setmaxmem(dom, memory)
-        xc.domain_memory_increase_reservation(dom, memory)
-        if cpu != -1:
-            xc.domain_pincpu(dom, 0, 1<<int(cpu))
-        log.debug('init_domain> Created domain=%d name=%s memory=%d', dom, self.name, memory)
-        self.setdom(dom)
-
-    def build_domain(self, ostype, kernel, ramdisk, cmdline, memmap):
-        """Build the domain boot image.
-        """
-        if self.recreate or self.restore: return
-        if not os.path.isfile(kernel):
-            raise VmError('Kernel image does not exist: %s' % kernel)
-        if ramdisk and not os.path.isfile(ramdisk):
-            raise VmError('Kernel ramdisk does not exist: %s' % ramdisk)
-        if len(cmdline) >= 256:
-            log.warning('kernel cmdline too long, domain %d', self.id)
-        dom = self.id
-        buildfn = getattr(xc, '%s_build' % ostype)
-        flags = 0
-        if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
-        if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
-        #todo generalise this
-        if ostype == "vmx":
-            log.debug('building vmx domain')            
-            err = buildfn(dom            = dom,
-                          image          = kernel,
-                          control_evtchn = 0,
-                          memsize        = self.memory,
-                          memmap         = memmap,
-                          cmdline        = cmdline,
-                          ramdisk        = ramdisk,
-                          flags          = flags)
-        else:
-            log.debug('building dom with %d vcpus', self.vcpus)
-            err = buildfn(dom            = dom,
-                          image          = kernel,
-                          control_evtchn = self.channel.getRemotePort(),
-                          cmdline        = cmdline,
-                          ramdisk        = ramdisk,
-                          flags          = flags,
-                          vcpus          = self.vcpus)
-            if err != 0:
-                raise VmError('Building domain failed: type=%s dom=%d err=%d'
-                              % (ostype, dom, err))
-            
-    def create_domain(self, ostype, kernel, ramdisk, cmdline, memmap=''):
-        """Create a domain. Builds the image but does not configure it.
-
-        @param ostype:  OS type
-        @param kernel:  kernel image
-        @param ramdisk: kernel ramdisk
-        @param cmdline: kernel commandline
-        """
-
-        self.create_channel()
-        self.build_domain(ostype, kernel, ramdisk, cmdline, memmap)
-        self.image = kernel
-        self.ramdisk = ramdisk
-        self.cmdline = cmdline
+        dom = self.image.initDomain(self.id, self.memory, cpu, self.cpu_weight)
+        log.debug('init_domain> Created domain=%d name=%s memory=%d',
+                  dom, self.name, self.memory)
+        if not self.restore:
+            self.setdom(dom)
 
     def create_channel(self):
         """Create the control channel to the domain.
@@ -773,43 +680,6 @@ class XendDomainInfo:
                 ctrl.initController(reboot=True)
         else:
             self.create_configured_devices()
-        if self.is_vmx:
-            self.create_vmx_model()
-
-    def create_vmx_model(self):
-        #todo: remove special case for vmx
-        device_model = sxp.child_value(self.config, 'device_model')
-        if not device_model:
-            raise VmError("vmx: missing device model")
-        device_config = sxp.child_value(self.config, 'device_config')
-        if not device_config:
-            raise VmError("vmx: missing device config")
-        #todo: self.memory?
-        memory = sxp.child_value(self.config, "memory")
-        # Create an event channel
-        device_channel = channel.eventChannel(0, self.id)
-        # see if a vncviewer was specified
-        # XXX RN: bit of a hack. should unify this, maybe stick in config space
-        vncconnect=""
-        image = sxp.child_value(self.config, "image")
-        args = sxp.child_value(image, "args")
-        if args:
-            arg_list = string.split(args)
-            for arg in arg_list:
-                al = string.split(arg, '=')
-                if al[0] == "VNC_VIEWER":
-                    vncconnect=" -v %s" % al[1]
-                    break
-
-        # Execute device model.
-        #todo: Error handling
-        # XXX RN: note that the order of args matter!
-        os.system(device_model
-                  + " -f %s" % device_config
-                  + vncconnect
-                  + " -d %d" % self.id
-                  + " -p %d" % device_channel['port1']
-                  + " -m %s" % memory)
 
     def device_create(self, dev_config):
         """Create a new device.
@@ -862,9 +732,7 @@ class XendDomainInfo:
     def configure_bootloader(self):
         """Configure boot loader.
         """
-        bl = sxp.child_value(self.config, "bootloader")
-        if bl is not None:
-            self.bootloader = bl
+        self.bootloader = sxp.child_value(self.config, "bootloader")
 
     def configure_console(self):
         """Configure the vm console port.
@@ -1052,19 +920,6 @@ class XendDomainInfo:
                 log.warning("Unknown config field %s", field_name)
             index[field_name] = field_index + 1
 
-    def pgtable_size(self, memory):
-        """Return the size of memory needed for 1:1 page tables for physical
-           mode.
-
-        @param memory: size in MB
-        @return size in KB
-        """
-        if self.is_vmx:
-            # Logic x86-32 specific. 
-            # 1 page for the PGD + 1 pte page for 4MB of memory (rounded)
-            return (1 + ((memory + 3) >> 2)) * 4
-        return 0
-
     def mem_target_set(self, target):
         """Set domain memory target in pages.
         """
@@ -1091,83 +946,6 @@ class XendDomainInfo:
             return 0
         return timeout - (time.time() - self.shutdown_pending['start'])
 
-def vm_image_linux(vm, image):
-    """Create a VM for a linux image.
-
-    @param name:      vm name
-    @param memory:    vm memory
-    @param image:     image config
-    @return: vm
-    """
-    kernel = sxp.child_value(image, "kernel")
-    cmdline = ""
-    ip = sxp.child_value(image, "ip", None)
-    if ip:
-        cmdline += " ip=" + ip
-    root = sxp.child_value(image, "root")
-    if root:
-        cmdline += " root=" + root
-    args = sxp.child_value(image, "args")
-    if args:
-        cmdline += " " + args
-    ramdisk = sxp.child_value(image, "ramdisk", '')
-    log.debug("creating linux domain with cmdline: %s" %(cmdline,))
-    vm.create_domain("linux", kernel, ramdisk, cmdline)
-    return vm
-
-def vm_image_plan9(vm, image):
-    """Create a VM for a Plan 9 image.
-
-    name      vm name
-    memory    vm memory
-    image     image config
-
-    returns vm 
-    """
-    kernel = sxp.child_value(image, "kernel")
-    cmdline = ""
-    ip = sxp.child_value(image, "ip", "dhcp")
-    if ip:
-        cmdline += "ip=" + ip
-    root = sxp.child_value(image, "root")
-    if root:
-        cmdline += "root=" + root
-    args = sxp.child_value(image, "args")
-    if args:
-        cmdline += " " + args
-    ramdisk = sxp.child_value(image, "ramdisk", '')
-    log.debug("creating plan9 domain with cmdline: %s" %(cmdline,))
-    vm.create_domain("plan9", kernel, ramdisk, cmdline)
-    return vm
-    
-def vm_image_vmx(vm, image):
-    """Create a VM for the VMX environment.
-
-    @param name:      vm name
-    @param memory:    vm memory
-    @param image:     image config
-    @return: vm
-    """
-    kernel = sxp.child_value(image, "kernel")
-    cmdline = ""
-    ip = sxp.child_value(image, "ip", "dhcp")
-    if ip:
-        cmdline += " ip=" + ip
-    root = sxp.child_value(image, "root")
-    if root:
-        cmdline += " root=" + root
-    args = sxp.child_value(image, "args")
-    if args:
-        cmdline += " " + args
-    ramdisk = sxp.child_value(image, "ramdisk", '')
-    memmap = sxp.child_value(vm.config, "memmap", '')
-    memmap = sxp.parse(open(memmap))[0]
-    from xen.util.memmap import memmap_parse
-    memmap = memmap_parse(memmap)
-    log.debug("creating vmx domain with cmdline: %s" %(cmdline,))
-    vm.create_domain("vmx", kernel, ramdisk, cmdline, memmap)
-    return vm
-
 def vm_field_ignore(vm, config, val, index):
     """Dummy config field handler used for fields with built-in handling.
 
@@ -1197,9 +975,16 @@ def vm_field_maxmem(vm, config, val, index):
 
 #============================================================================
 # Register image handlers.
-add_image_handler('linux', vm_image_linux)
-add_image_handler('plan9', vm_image_plan9)
-add_image_handler('vmx',   vm_image_vmx)
+from image import          \
+     addImageHandlerClass, \
+     ImageHandler,         \
+     LinuxImageHandler,    \
+     Plan9ImageHandler,    \
+     VmxImageHandler
+
+addImageHandlerClass(LinuxImageHandler)
+addImageHandlerClass(Plan9ImageHandler)
+addImageHandlerClass(VmxImageHandler)
 
 # Ignore the fields we already handle.
 add_config_handler('name',       vm_field_ignore)
diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py
new file mode 100644 (file)
index 0000000..09fe390
--- /dev/null
@@ -0,0 +1,338 @@
+import os
+
+import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
+from xen.xend import sxp
+from xen.xend.XendError import VmError
+from xen.xend.XendLogging import log
+#from xen.xend.xenstore import DBVar
+
+class ImageHandler:
+    """Abstract base class for image handlers.
+
+    initDomain() is called to initialise the domain memory.
+    
+    createImage() is called to configure and build the domain from its
+    kernel image and ramdisk etc.
+
+    The method buildDomain() is used to build the domain, and must be
+    defined in a subclass.  Usually this is the only method that needs
+    defining in a subclass.
+
+    The method createDeviceModel() is called to create the domain device
+    model if it needs one.  The default is to do nothing.
+
+    The method destroy() is called when the domain is destroyed.
+    The default is to do nothing.
+    
+    """
+
+    #======================================================================
+    # Class vars and methods.
+
+    """Table of image handler classes for virtual machine images.
+    Indexed by image type.
+    """
+    imageHandlerClasses = {}
+
+    def addImageHandlerClass(cls, h):
+        """Add a handler class for an image type
+        @param h:        handler: ImageHandler subclass
+        """
+        cls.imageHandlerClasses[h.ostype] = h
+
+    addImageHandlerClass = classmethod(addImageHandlerClass)
+
+    def findImageHandlerClass(cls, image):
+        """Find the image handler class for an image config.
+
+        @param image config
+        @return ImageHandler subclass or None
+        """
+        ty = sxp.name(image)
+        if ty is None:
+            raise VmError('missing image type')
+        imageClass = cls.imageHandlerClasses.get(ty)
+        if imageClass is None:
+            raise VmError('unknown image type: ' + ty)
+        return imageClass
+
+    findImageHandlerClass = classmethod(findImageHandlerClass)
+
+    def create(cls, vm, image):
+        """Create an image handler for a vm.
+
+        @param vm vm
+        @param image image config
+        @return ImageHandler instance
+        """
+        imageClass = cls.findImageHandlerClass(image)
+        return imageClass(vm, image)
+
+    create = classmethod(create)
+
+    #======================================================================
+    # Instance vars and methods.
+
+    #db = None
+    ostype = None
+
+    config = None
+    kernel = None
+    ramdisk = None
+    cmdline = None
+    flags = 0
+
+    #__exports__ = [
+    #    DBVar('ostype',  ty='str'),
+    #    DBVar('config',  ty='sxpr'),
+    #    DBVar('kernel',  ty='str'),
+    #    DBVar('ramdisk', ty='str'),
+    #    DBVar('cmdline', ty='str'),
+    #    DBVar('flags',   ty='int'),
+    #    ]
+
+    def __init__(self, vm, config):
+        self.vm = vm
+        #self.db = vm.db.addChild('/image')
+        self.config = config
+
+    #def exportToDB(self, save=False):
+    #    self.db.exportToDB(self, fields=self.__exports__, save=save)
+
+    #def importFromDB(self):
+    #    self.db.importFromDB(self, fields=self.__exports__)
+
+    def unlink(self, f):
+        if not f: return
+        try:
+            os.unlink(f)
+        except OSError, ex:
+            log.warning("error removing bootloader file '%s': %s", f, ex)
+
+    def initDomain(self, dom, memory, cpu, cpu_weight):
+        """Initial domain create.
+
+        @return domain id
+        """
+
+        mem_kb = self.getDomainMemory(memory)
+        if not self.vm.restore:
+            dom = xc.domain_create(dom = dom or 0)
+            # if bootloader, unlink here. But should go after buildDomain() ?
+            if self.vm.bootloader:
+                self.unlink(self.kernel)
+                self.unlink(self.ramdisk)
+            if dom <= 0:
+                raise VmError('Creating domain failed: name=%s' % self.vm.name)
+        log.debug("initDomain: cpu=%d mem_kb=%d dom=%d", cpu, mem_kb, dom)
+        # xc.domain_setuuid(dom, uuid)
+        xc.domain_setcpuweight(dom, cpu_weight)
+        xc.domain_setmaxmem(dom, mem_kb)
+        xc.domain_memory_increase_reservation(dom, mem_kb)
+        if cpu != -1:
+            xc.domain_pincpu(dom, 0, 1<<int(cpu))
+        return dom
+
+    def createImage(self):
+        """Entry point to create domain memory image.
+        Override in subclass  if needed.
+        """
+        self.configure()
+        self.createDomain()
+
+    def configure(self):
+        """Config actions common to all unix-like domains."""
+        self.kernel = sxp.child_value(self.config, "kernel")
+        self.cmdline = ""
+        ip = sxp.child_value(self.config, "ip", None)
+        if ip:
+            self.cmdline += " ip=" + ip
+        root = sxp.child_value(self.config, "root")
+        if root:
+            self.cmdline += " root=" + root
+        args = sxp.child_value(self.config, "args")
+        if args:
+            self.cmdline += " " + args
+        self.ramdisk = sxp.child_value(self.config, "ramdisk", '')
+        
+    def createDomain(self):
+        """Build the domain boot image.
+        """
+        # Set params and call buildDomain().
+        self.flags = 0
+        if self.vm.netif_backend: self.flags |= SIF_NET_BE_DOMAIN
+        if self.vm.blkif_backend: self.flags |= SIF_BLK_BE_DOMAIN
+
+        if self.vm.recreate or self.vm.restore:
+            return
+        if not os.path.isfile(self.kernel):
+            raise VmError('Kernel image does not exist: %s' % self.kernel)
+        if self.ramdisk and not os.path.isfile(self.ramdisk):
+            raise VmError('Kernel ramdisk does not exist: %s' % self.ramdisk)
+        if len(self.cmdline) >= 256:
+            log.warning('kernel cmdline too long, domain %d', self.vm.getDomain())
+        
+        log.info("buildDomain os=%s dom=%d vcpus=%d", self.ostype,
+                 self.vm.getDomain(), self.vm.vcpus)
+        err = self.buildDomain()
+        if err != 0:
+            raise VmError('Building domain failed: ostype=%s dom=%d err=%d'
+                          % (self.ostype, self.vm.getDomain(), err))
+
+    def getDomainMemory(self, mem_mb):
+        """Memory (in KB) the domain will need for mem_mb (in MB)."""
+        return mem_mb * 1024
+
+    def buildDomain(self):
+        """Build the domain. Define in subclass."""
+        raise NotImplementedError()
+
+    def createDeviceModel(self):
+        """Create device model for the domain (define in subclass if needed)."""
+        pass
+    
+    def destroy(self):
+        """Extra cleanup on domain destroy (define in subclass if needed)."""
+        pass
+
+addImageHandlerClass = ImageHandler.addImageHandlerClass
+
+class LinuxImageHandler(ImageHandler):
+
+    ostype = "linux"
+
+    def buildDomain(self):
+        #if self.vm.store_channel:
+        #    store_evtchn = self.vm.store_channel.port2
+        #else:
+        #    store_evtchn = 0
+        d  = xc.linux_build(dom            = self.vm.getDomain(),
+                            image          = self.kernel,
+                            control_evtchn = self.vm.channel.getRemotePort(),
+                            #store_evtchn   = store_evtchn,
+                            cmdline        = self.cmdline,
+                            ramdisk        = self.ramdisk,
+                            flags          = self.flags,
+                            vcpus          = self.vm.vcpus)
+        #if isinstance(d, dict):
+        #    self.vm.store_mfn = d.get('store_mfn')
+        return 0
+
+class Plan9ImageHandler(ImageHandler):
+
+    ostype = "plan9"
+
+    def buildDomain(self):
+        return xc.plan9_build(dom            = self.vm.getDomain(),
+                              image          = self.kernel,
+                              control_evtchn = self.vm.channel.getRemotePort(),
+                              cmdline        = self.cmdline,
+                              ramdisk        = self.ramdisk,
+                              flags          = self.flags,
+                              vcpus          = self.vm.vcpus)
+
+class VmxImageHandler(ImageHandler):
+
+    #__exports__ = ImageHandler.__exports__ + [
+    #    DBVar('memmap',        ty='str'),
+    #    DBVar('memmap_value',  ty='sxpr'),
+    #    # device channel?
+    #    ]
+    
+    ostype = "vmx"
+    memmap = None
+    memmap_value = None
+    device_channel = None
+
+    def createImage(self):
+        """Create a VM for the VMX environment.
+        """
+        self.configure()
+        self.parseMemmap()
+        self.createDomain()
+
+    def buildDomain(self):
+        return xc.vmx_build(dom            = self.vm.getDomain(),
+                            image          = self.kernel,
+                            control_evtchn = 0,
+                            memsize        = self.vm.memory,
+                            memmap         = self.memmap_value,
+                            cmdline        = self.cmdline,
+                            ramdisk        = self.ramdisk,
+                            flags          = self.flags)
+
+    def parseMemmap(self):
+        self.memmap = sxp.child_value(self.vm.config, "memmap")
+        if self.memmap is None:
+            raise VmError("missing memmap")
+        memmap = sxp.parse(open(self.memmap))[0]
+        from xen.util.memmap import memmap_parse
+        self.memmap_value = memmap_parse(memmap)
+        
+    def createDeviceModel_old(self):
+        device_model = sxp.child_value(self.vm.config, 'device_model')
+        if not device_model:
+            raise VmError("vmx: missing device model")
+        device_config = sxp.child_value(self.vm.config, 'device_config')
+        if not device_config:
+            raise VmError("vmx: missing device config")
+        # Create an event channel.
+        self.device_channel = channel.eventChannel(0, self.vm.getDomain())
+        # Execute device model.
+        #todo: Error handling
+        os.system(device_model
+                  + " -f %s" % device_config
+                  + " -d %d" % self.vm.getDomain()
+                  + " -p %d" % self.device_channel['port1']
+                  + " -m %s" % self.vm.memory)
+
+    def createDeviceModel(self):
+        device_model = sxp.child_value(self.vm.config, 'device_model')
+        if not device_model:
+            raise VmError("vmx: missing device model")
+        device_config = sxp.child_value(self.vm.config, 'device_config')
+        if not device_config:
+            raise VmError("vmx: missing device config")
+        # Create an event channel
+        self.device_channel = channel.eventChannel(0, self.vm.getDomain())
+        # Execute device model.
+        #todo: Error handling
+        # XXX RN: note that the order of args matter!
+        os.system(device_model
+                  + " -f %s" % device_config
+                  + self.vncParams()
+                  + " -d %d" % self.vm.getDomain()
+                  + " -p %d" % self.device_channel['port1']
+                  + " -m %s" % self.vm.memory)
+
+    def vncParams(self):
+        # see if a vncviewer was specified
+        # XXX RN: bit of a hack. should unify this, maybe stick in config space
+        vncconnect=""
+        image = self.config
+        args = sxp.child_value(image, "args")
+        if args:
+            arg_list = string.split(args)
+            for arg in arg_list:
+                al = string.split(arg, '=')
+                if al[0] == "VNC_VIEWER":
+                    vncconnect=" -v %s" % al[1]
+                    break
+        return vncconnect
+
+    def destroy(self):
+        channel.eventChannelClose(self.device_channel)
+
+    def getDomainMemory(self, mem_mb):
+        return (mem_mb * 1024) + self.getPageTableSize(mem_mb)
+            
+    def getPageTableSize(self, mem_mb):
+        """Return the size of memory needed for 1:1 page tables for physical
+           mode.
+
+        @param mem_mb: size in MB
+        @return size in KB
+        """
+        # Logic x86-32 specific. 
+        # 1 page for the PGD + 1 pte page for 4MB of memory (rounded)
+        return (1 + ((mem_mb + 3) >> 2)) * 4